#include <stdlib.h>
 
#include "random.h"
#include "trafgen.h"
#include "ranvar.h"

class GAMING : public TrafficGenerator {
private:
	enum { DL = 0, UL = 1 } direction_;
public:
	GAMING();
	virtual double next_interval(int&);
	virtual void timeout();
	int command(int argc, const char*const* argv);
protected:

	void init();

	double client_rate_;
	double ipt_scale_;
	double ipt_shape_;
	double bpo_scale_;
	double bpo_shape_;

	WeibullRandomVariable inter_page_time;
	WeibullRandomVariable bytes_per_object;
};

static class GAMINGClass : public TclClass
{
public:
	GAMINGClass() : TclClass("Application/Traffic/GAMING") {}
	TclObject* create(int, const char*const*) {
   		return (new GAMING());
   	}
} class_GAMING;

int GAMING::command(int argc, const char*const* argv)
{
	if ( argc == 3 && strcmp(argv[1], "direction") == 0) {
		if ( (strcmp(argv[2], "ul") == 0 ) ||
				(strcmp(argv[2], "UL") == 0) ) {
			// Set uplink direction.
			direction_ = UL;
			return TCL_OK;
		}
		else if ( (strcmp(argv[2], "dl") == 0 ) ||
				(strcmp(argv[2], "DL") == 0) ) {
			// Set downlink direction.
			direction_ = DL;
			return TCL_OK;
		}
		else {
			fprintf ( stderr, "GAMING: invalid direction\n");
			return TCL_ERROR;
		}
	}

	if ( argc == 3 && strcmp(argv[1], "client-rate") == 0) {
		// Set sampling rate client-side.
		client_rate_ = atof(argv[2]);
		return TCL_OK;
	}

	if (argc == 3 && strcmp(argv[1], "use-rng") == 0) {
		inter_page_time.seed((char *)argv[2]);
		bytes_per_object.seed((char *)argv[2]);
		return TCL_OK;
	} 

	return Application::command(argc,argv);
}

GAMING::GAMING() : inter_page_time (0.0, 0.0),
	bytes_per_object (0.0, 0.0)
{
	bind_time ("ipt_scale_", &ipt_scale_);
	bind_time ("ipt_shape_", &ipt_shape_);
	bind ("bpo_shape_", &bpo_scale_);
	bind ("bpo_shape_", &bpo_shape_);
}

void GAMING::init()
{
	inter_page_time.setshape(ipt_shape_);
	inter_page_time.setscale(ipt_scale_);
	bytes_per_object.setshape(bpo_shape_);
	bytes_per_object.setscale(bpo_scale_);
	if (agent_) {
		if ( agent_->get_pkttype() != PT_TCP &&
				agent_->get_pkttype() != PT_TFRC) {

			agent_->set_pkttype(PT_EXP);
		}
	}
}

double GAMING::next_interval(int& size)
{
	// Get object's size.
	size = 0;
	size += int ( bytes_per_object.value() + .5);
	if (size == 0) size = 1;
	
	if ( direction_ == UL ) {
		// Client --> Server ( uplink connection )
		// It's the sampling ratio client-side.
		return client_rate_;
	}

	// Server --> Client ( downlink connection )
	// We shall obtain the interval between consecutive packets.
	return inter_page_time.value();
}

void GAMING::timeout()
{
	if (! running_)
		return;

	/* send a packet */
	// The test tcl/ex/test-rcvr.tcl relies on the "NEW_BURST" flag being 
	// set at the start of any exponential burst ("talkspurt").  
	if (nextPkttime_ == -1)
		agent_->sendmsg(size_, "NEW_BURST");
	else
		agent_->sendmsg(size_);
	/* figure out when to send the next one */
	nextPkttime_ = next_interval(size_);
	/* schedule it */
	if (nextPkttime_ > 0)
		timer_.resched(nextPkttime_);
}
